﻿<html xmlns:MSHelp="http://msdn.microsoft.com/mshelp" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xanx="http://schemas.microsoft.com/developer/xanx/2005"><head><META http-equiv="Content-Type" content="text/html; charset=utf-8"><META NAME="save" CONTENT="history"><title>Non-Realistic Rendering Sample</title>
<style><!--
/***********************************************************
 *             SCRIPT-SUPPORTING STYLES
 ***********************************************************/

/* Defines the userData cache persistence mechanism. */
.userDataStyle
{
	behavior: url(#default#userData);
}

/* Used to save the scroll bar position when navigating away from a page. */
div.saveHistory
{
	behavior: url(#default#saveHistory);
}

/* Formats the expand/collapse images for all collapsible regions. */
img.toggle
{
	border: 0;
	margin-right: 5;
}

/* Formats the Language filter drop-down image. */
img#languageFilterImage
{
	border: 0;
	margin-left: 0;
	vertical-align: middle;
}

/* Formats the Members Options filter drop-down image. */
img#membersOptionsFilterImage
{
	border: 0;
	margin-left: 0;
	vertical-align: middle;
}

/* Formats the Collapse All/Expand All images. */
img#toggleAllImage
{
	margin-left: 0;
	vertical-align: middle;
}

/* Supports XLinks */
MSHelp\:link
{
 	text-decoration: underline;
	color: #0000ff; 
	hoverColor: #3366ff;
	filterString: ;
}


body
	{
	background:	#FFFFFF;
	color: #000000;
	font-family:	Verdana;
	font-size: medium;
	font-style: normal;
	font-weight: normal;
	margin-top:	0;
	margin-bottom:	0;
	margin-left:	0;
	margin-right:	0;
	width:	100%;
	/*font-size: 110%;*/
	}

div.section
	{
	margin-left: 15px;
	}

div.hxnx5
	{
	margin-left: 1.5em;
	}

/* Font for all headings */	
h1, h2, h3, h4, h5, h6
	{
	font-family: Verdana, Arial, Helvetica, sans-serif;
	margin-top: 18;
	margin-bottom: 8; 
	font-weight: bold;
	}
h1
	{
	font-size: 130%;
	color: #003399;
	}
div#scrollyes h1 /* Changes font size for full-scrolling topic */
	{
	font-size: 150%;
	}
h2
	{
	font-size: 125%;
	}
h3
	{
	font-size: 115%;
	margin-top: 9;
	margin-bottom: 4; 
	}
h4
	{
	font-size: 115%;
	margin-top: 9;
	margin-bottom: 4; 
	}
h5
	{
	font-size: 100%;
	margin-top: 9;
	margin-bottom: 4; 
	}
h6
	{
	font-size: 100%;
	margin-top: 9;
	margin-bottom: 4; 
	}

ul p, ol p, dl p
	{
	margin-left: 0em;
	}

p
	{
	margin-top: .6em;
	margin-bottom: .6em;
	}
	
td p
	{
	margin-top: 0.0em;
	margin-bottom: 0.6em;
	}

dd p
	{
	margin-top: 0.0em;
	margin-bottom: 0.6em;
	}

.image
	{
	text-align: center;
	}

dl
	{
	margin-top: 0em; 
	margin-bottom: 1.3em;
	}

dd
	{
	margin-bottom: 0em;
	margin-left: 0;
	}

dl.glossary dd 
{
	margin-bottom: 0em;  
	margin-left: 1.5em; 
}

dt
	{
	margin-top: .6em;
	margin-bottom: 1;
	}

ul, ol
	{
	margin-top: 0.6em;
	margin-bottom: 0.6em; 	
	}
	
ol
	{
	margin-left: 2.5em; 
	
	}	
	
ul
	{
	list-style-type: disc; 
	margin-left: 1.9em; 
	}

li
	{
	margin-bottom: 0.4em;
	}

ul ol, ol ol
	{
	list-style-type: lower-alpha;
	}

pre
	{
	margin-top: .6em;
	margin-bottom: .6em; 
	}

pre
	{
	font: 105% Lucida, mono; 
	color: #000066;
	}

code
{
	font-family: Monospace, Courier New, Courier;
	font-size: 105%;
	color:	#000066;
}

table.userdata td 
	{
	background: #ffffff;
	background-color: #F5F5F5;
	border-color: #ffffff;
	border: none;
	}	
table.clsWarning
	{
	background: #ffffff;
	padding: 0px;
	margin: 0px;
	border: none;
	}
table.clsWarning td
	{
	padding: 0px;
	margin: 0px;
	background: #ffffff;
	vertical-align: middle;
	font-size: 70%;
	}

div#mainSection table
	{
	width: 98%;
	background: #ffffff;
	margin-top: 5px;
	margin-bottom: 5px;
	}

div#mainSection table th
	{ 
	padding: 5px 6px;
	background: #EFEFF7;
	text-align: left;
	font-size: 70%;
	vertical-align: bottom;
	border-bottom: 1px solid #C8CDDE;
	}
div#mainSection table td
	{ 
	padding: 5px 5px;
	background: #F7F7FF;
	vertical-align: top;
	font-size: 70%;
	border-bottom: 1px solid #D5D5D3;
	}

div#syntaxCodeBlocks table th
	{
	padding: 1px 6px;
	color: #000066;
	}

div#syntaxCodeBlocks table td
	{
	padding: 1px 5px;
	}

/* Applies to the running header text in the first row of the upper table in the
   non-scrolling header region. */
span#runningHeaderText
{
	color: #003399;
	font-size: 90%;
	padding-left: 13;
}

/* Applies to the topic title in the second row of the upper table in the
   non-scrolling header region. */
span#nsrTitle
{
	color: #003399;
	font-size: 120%;
	font-weight: 600;
	padding-left: 13;
}

/* Applies to everything below the non-scrolling header region. */
div#mainSection
{
	font-size: 70%;
	width: 100%;
}

/* Applies to everything below the non-scrolling header region, minus the footer. */
div#mainBody
{
	font-size: 90%;
	margin-left: 15;
	margin-top: 10;
	padding-bottom: 20;
}

/* Adds right padding for all blocks in mainBody */
div#mainBody p, div#mainBody ol, div#mainBody ul, div#mainBody dl
{
	padding-right: 5;
}

div#mainBody div.alert, div#mainBody div.code, div#mainBody div.tableSection
{
	width:98.9%;
}

div.alert p, div.code p
{
	margin-top:5;
	margin-bottom:8;
}

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Begin Note Styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
div#mainSection div.alert table
{
	border: 0;
}

div#mainSection div.alert table th
{
	padding-top: 0;
	padding-bottom: 0;
	padding-left: 5;
	padding-right: 5;
}

div#mainSection div.alert table td
{
	padding-left: 5;
	padding-right: 5;
}

img.note
{
	border: 0;
	margin-left: 0;
	margin-right: 3;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - End Note Styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Begin Non-scrolling Header Region Styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* Applies to the entire non-scrolling header region. */
div#header
{
	background-color: #D4DFFF;
	padding-top:	0;
	padding-bottom:	0;
	padding-left:	0;
	padding-right:	0;
	width:	100%;
}

/* Applies to both tables in the non-scrolling header region. */
div#header table
{
	margin-top:	0;
	margin-bottom: 0;
	border-bottom-color: #C8CDDE;
	border-bottom-style: solid;
	border-bottom-width: 1;
	background: #D4DFFF;
	width:	100%;
}

/* Applies to cells in both tables in the non-scrolling header region. */
div#header table td
{
	color: #0000FF;
	font-size: 70%;
	padding-right: 20;
	padding-top: 1;
	padding-bottom: 1;
	border: none;
	background: #D4DFFF;
}

/* Applies to the last row in the upper table of the non-scrolling header region. Text 
   in this row includes See Also, Constructors, Methods, and Properties. */
div#header table tr#headerTableRow3 td
{
	padding-bottom: 2;
	padding-top: 5;
	padding-left: 15;
}

/* Applies to the lower table in the non-scrolling header region. Text in this table
   includes Collapse All/Expand All, Language Filter, and Members Options. */
div#header table#bottomTable
{
	border-top-color: #FFFFFF;
	border-top-style: solid;
	border-top-width: 1;
	text-align: left;
	padding-left: 15;
}


blockquote
	{
	margin-left: 3.8em;
	margin-right: 3.8em;
	margin-top: .6em;
	margin-bottom: .6em;
	}

sup
	{
	text-decoration: none;
	font-size: smaller; 
	}

a:link
	{
	color: #0000FF;
/*    font-weight: bold */
	}
	
a:visited
	{
	color: #0000AA;
/*    font-weight: bold	*/
	}
	
a:hover
	{
	color: #3366FF;
/*    font-weight: bold */
	}
	
.label
	{
	font-weight: bold; 
	margin-top: 1em;
	margin-left: -26px;
	}
	
.tl
	{
	margin-bottom: .75em; 
	}
	
.atl
	{
	padding-left: 1.5em;
	padding-bottom: .75em; 
	}
	
.cfe
	{
	font-weight: bold; 
	}
	
.mini
	{
	font-size: smaller;
	}
	
.dt
	{
	margin-bottom: -.6em; 
	}
	
.indent
	{
	margin-left: 1.9em; 
	margin-right: 1.9em;
	}

.product
	{
	text-align: right;
	color: #333333;
	font-size: smaller;
	font-style: italic;
	}

.buttonbarshade
	{
	position: relative;
	margin: 0;
	left: 0px;
	top: 2;
	width: 50%;
	height: 40px;
	}

.buttonbartable
	{
	position: absolute;
	margin: 0;
	padding:0;
	border:0;
	left:0px;
	top: 2;
	width: 100%;
	height: 40px;
	}

/* background color, font for header */ 
table.buttonbartable td, table.buttonbarshade td
	{
	background: #ffffff; /*#5177B8; #80C615;*/
	border-left: 0px solid #80C615;
	margin: 0;
	padding: 0px 0px 0px 0px;
	font-family: Impact, sans-serif;
	font-size: 14pt;
	}

table.buttonbartable td.button1
	{
	background: #5177B8; /*#80C615;*/;
	padding: 0;
	font-weight: bold;
	text-align: center;
	cursor: hand;
	}

table.buttonbartable td.button2
	{
	background: #5177B8; /*#80C615;*/;
	font-weight: bold;
	text-align: center;
	}

table.buttonbartable td.button3
	{
	background: #5177B8; /*#80C615;*/;
	font-weight: bold;
	text-align: center;
	}

table.buttonbartable td.runninghead
	{
	padding-left: 0px;
	font-style: italic;
	text-align: left;
	}

.version
	{
	text-align: left;
	color: #000000;
	margin-top: 3em;
	margin-left: -26px;
	font-size: smaller;
	font-style: italic;
	}

.lang, .ilang
	{
	color: #0000ff;
	font: normal 7pt Arial, Helvetica, sans-serif;
	}

div.langMenu
	{
	position: absolute;
	z-index: 1;
	width: 96pt;
	padding: 8pt;
	visibility: hidden;
	border: 1px solid #000000;
	background: #ffffd0;
	}

div.langMenu ul
	{
	padding-left: 2em;
	margin-left: 0;
	}

div.filtered
	{
	margin: 4pt 0 8pt -26px;
	padding: 4px 4px 8px 26px;
	width: 100%;
	border: 2px solid #aaaacc;
	background: #ffffff;
	}

div.filtered2
	{
	margin: 4pt 0 8pt -26px;
	padding: 4px 4px 8px 26px;
	width: 100%;
	border: none;
	background: #ffffff;
	}

div.filtered h1, div.filtered h2, div.filtered h3, div.filtered h4
	{
	margin-left: -22px;
	}

div.filtered span.lang
	{
	position: relative;
	left: -22px;
	}

div.reftip
	{
	position: absolute;
	z-index: 1;
	padding: 8pt;
	visibility: hidden;
	border: 1px solid #000000;
	background: #ffffd0;
	}

a.synParam
	{
	color: #0000FF;
	/*color: #3F7800;*/ 	
	/*color: #8DC54F;*/
	text-decoration: none;
    font-weight: normal;
	}

a.synParam:hover
	{
	text-decoration: underline;
    font-weight: normal;
	}

div.sapop
	{
	position: absolute;
	z-index: 1;
	left: 26px;
	width: 100%;
	padding: 10px 10px 10px 36px;
	visibility: hidden;
	border: 1px solid #000000;
	background: #ffffd0;
	}

div.footer
	{
	width: 100%;
	border: none;
	background: #ffffff;
	margin-top: 18pt;
	padding-bottom: 12pt;
	color: #0000FF;
	/*color: #228B22; */
	text-align: center;
	font-size: 76%;
	}

div.preliminary
	{
	margin-top: 8pt;
	padding-bottom: 12pt;
	color: #A0A0A0;
	}

/* A procedure section. eg. 'To create a file', 'To add a value' */
div.proc
    {
	margin-left: 0.5em; 
    }
     
/* The title of a 'procedure' section. */
div.proc h3
    {
	font-family: Verdana, Arial, Helvetica, sans-serif;
	font-weight: bold;
	font-size: 115%;
	margin-top: 1em;
	margin-bottom: 0.4em;
	margin-left: -0.5em; 
	color: #003399;
    }

div.proc ul
    {
    margin-left: 1.5em;
    }

div.proc ol
    {
    margin-left: 2.0em;
    }
      
.note
	{
	margin-left: 14pt;
	margin-right: 12pt;
	}

.indent1
	{
	margin-left: 12pt;
	}

.indent2
	{
	margin-left: 24pt;
	}

.indent3
	{
	margin-left: 36pt;
	}

p.proch
	{
	padding-left: 16px;
	}

p.proch img
	{
	position: relative; 
	vertical-align: top;
	left: -18px; 
	margin-right: -14px; 
	margin-bottom: -18px;
	}
	
div.clsPlatSpec
{
	background-color:#FFF8DC;
	border-style:solid;
	border-width:1pt 0pt 0pt 1pt;
	border-color:#ffE4C4;
	margin-top:0.6em;
	width:100%;
}


/* Applies to the language labels in the Language Filter drop-down list. */
.languageFilter
{
	color:	#0000FF;
	cursor:hand;
	text-decoration:underline;
	padding-bottom:4;
}

/* Dropdown areas */

#languageSpan {
	position: absolute;
	visibility: hidden;
	border-style: solid;
	border-width: 1px;
	border-color: #C8CDDE;
	background: #d4dfff;
	padding: 4px;
	font-size: 70%;
}

#membersOptionsSpan {
	position: absolute;
	visibility: hidden;
	border-style: solid;
	border-width: 1px;
	border-color: #C8CDDE;
	background: #d4dfff;
	padding: 4px;
	font-size: 70%;
}
--></style>

<xml>
<MSHelp:TOCTitle Title="Non-Realistic Rendering Sample" />
<MSHelp:RLTitle Title="Non-Realistic Rendering Sample" />
<MSHelp:Keyword Index="A" Term="O:Microsoft.Xna.NonPhotoRealistic" />
<MSHelp:Keyword Index="A" Term="87df1b11-f2ac-d8ff-b9c7-ffe680b2fa1e" />
<MSHelp:Keyword Index="K" Term="Non-Realistic Rendering Sample" />
<MSHelp:Attr Name="ProjType" Value="LocalProj" />
<MSHelp:Attr Name="ProjType" Value="XNA" />
<MSHelp:Attr Name="DocSet" Value="XNA" />
<MSHelp:Attr Name="DocSet" Value="ExpressLibVS" />
<MSHelp:Attr Name="DocSet" Value="C#" />
<MSHelp:Attr Name="Locale" Value="en-us" />
<MSHelp:Attr Name="AssetID" Value="87df1b11-f2ac-d8ff-b9c7-ffe680b2fa1e" />
<MSHelp:Attr Name="TopicType" Value="kbOrient" />
</xml>
</head><body><div id="mainSection"><div id="mainBody">
  <h1>Non-Realistic Rendering Sample</h1>

  
    This sample shows how to implement stylized non-photorealistic rendering techniques such as cartoon shading, edge detection, and a pencil sketch effect.
  

  <a name="ID2EK"></a><h1 class="heading">Sample Overview</h1><div id="ID2EK" class="hxnx1">
    

    <p>The sample provides three specialized rendering techniques.</p>
    <ol>
      <li>Toon shading displays models using a banded lighting technique. Rather than the usual smooth gradients from light to dark, it uses just three discrete levels of brightness, with sudden transitions where the object goes from light into shadow.</li>
      <li>Edge detection adds black lines around the silhouette of the model.</li>
      <li>The sketch postprocess adds a pencil stroke pattern over the top of the scene.</li>
    </ol>
    <p>Many different graphical effects can be achieved by combining these techniques in various ways. For instance a cartoon effect is created by using the toon shading and edge detection together, or a pencil sketch effect by combining edge detection with the sketch postprocess.</p>

    <a name="ID2E2"></a><h2 class="subHeading">Minimum Shader Profile</h2><div id="ID2E2" class="hxnx2">
      
      <dl class="glossary">
        <dt>Vertex Shader Model 1.1</dt>
        <dt>Pixel Shader Model 2.0</dt>
      </dl>
    </div>

    <a name="ID2EHB"></a><h2 class="subHeading">Sample Controls</h2><div id="ID2EHB" class="hxnx2">
      
      <p>This sample uses the following keyboard and gamepad controls.</p>

      <table>
        <tr>
          <th>Action</th>
          <th>Keyboard Control</th>
          <th>Gamepad Control</th>
        </tr>
        <tr>
          <td>Change the display settings.</td>
          <td><b>A</b></td>
          <td><b>A</b></td>
        </tr>
        <tr>
          <td>Exit the sample.</td>
          <td>ESC or ALT+F4</td>
          <td><b>BACK</b></td>
        </tr>
      </table>
    </div>
  </div>

  <a name="ID2EQC"></a><h1 class="heading">How the Sample Works</h1><div id="ID2EQC" class="hxnx1">
    

    <a name="ID2EUC"></a><h2 class="subHeading">Toon Shading</h2><div id="ID2EUC" class="hxnx2">
      

      <p>Toon shading is implemented by the ToonPixelShader function in the CartoonEffect.fx file. This takes in a smoothly varying light amount that was computed by the vertex shader, and uses a series of <b>if/else</b> statements to quantize it into just three discrete levels of brightness.</p>

      <div class="code"><span codeLanguage="CSharp"><table><tr><th>C# </th></tr><tr><td><pre><pre>
    if (input.LightAmount &gt; ToonThresholds[0])
        light = ToonBrightnessLevels[0];
    else if (input.LightAmount &gt; ToonThresholds[1])
        light = ToonBrightnessLevels[1];
    else
        light = ToonBrightnessLevels[2];</pre></pre></td></tr></table></span></div>

      <p>For comparison, the <code>LambertPixelShader</code> function (which is used by a different technique in the same effect file) takes in the light amount from the same vertex shader, but instead uses this to compute a traditional smoothly varying light value. Both shaders then multiply their light amount with a color looked up from the model texture.</p>
      
      <p>The following figure shows the difference between conventional Lambert shading and the quantized toon shading effect.</p>
      
      <img src="Documentation/NonPhotoRealisticToon.png">
    </div>

    <a name="ID2EQD"></a><h2 class="subHeading">Edge Detection</h2><div id="ID2EQD" class="hxnx2">
      

      <p>Edge detection is implemented as post-processing effect, using a two-dimensional gradient filter. First, the model is drawn into a custom render target, using the <code>NormalDepth</code> technique from the CartoonEffect.fx file. Instead of outputting colors, this writes the surface normal into the red, green, and blue channels of the output color, and the depth into the alpha channel.</p>

      <p>The main scene is then drawn into a second render target, using either the Lambert or Toon lighting shaders as described above.</p>

      <p>Finally, a full-screen sprite is used to draw both of these custom render targets onto the back buffer, using the Postprocess.fx effect to apply the edge detection filter.</p>

      <p>For each pixel on the screen, this filter makes four lookups into the render target containing normal and depth information: one slightly to the top left of the current position, one to the top right, another to the bottom left, and finally one to the bottom right. It then compares the values obtained from these lookups to determine whether the normal or depth values are changing rapidly at the location of this pixel. If it detects a dramatic change, this must be an edge location; while if the normal and depth are similar in all directions, we must be inside a flat area of the scene.</p>

      <p>A threshold is used to reject very small changes in the normal or depth, which would otherwise cause false positive edges to be detected wherever the model contained a slight curve.</p>

      <p>This next figure shows the contents of the normal and depth render target (which are actually stored together in a single image, using the alpha channel to hold the depth values), along with the resulting edge information.</p>
      
      <img src="Documentation/NonPhotoRealisticEdges.png">

      <p>Once the edge data has been computed, this is combined with the color from the main scene render target, adding black lines around the silhouette of the object.</p>
      
      <p>It would also be possible to not bother rendering normals and depth to a special render target, and just run the edge detection filter directly over the main scene image instead. That can work well if your objects contain mostly flat colors, but it doesn't yield great results for textured models because it will incorrectly pick up an edge wherever the texture changes color. Doing the edge detection using normal and depth information gives higher-quality results, because it depends only on the shape of the objects rather than on how they have been textured.</p>

      <p>The depth edge detection works best if the camera near and far clip planes are set as close as possible to the models in the scene. If the near clip is very small, or the far clip is very distant, there may not be enough precision to produce good results from this (although the normal data will still be able to provide useful edge information).</p>
    </div>

    <a name="ID2ENE"></a><h2 class="subHeading">Pencil Sketch</h2><div id="ID2ENE" class="hxnx2">
      

      <p>The pencil sketch effect is implemented as a post-process, using the same Postprocess.fx effect that also provides the edge detection filter.</p>

      <p>It works by doing a lookup into a texture containing a pre-drawn pencil stroke pattern, and then combining this with the color from the main scene in such a way that there will be lots of strokes where the scene is dark, and less where it is light. The resulting value can either be used directly to produce a monochrome sketch effect, or multiplied with the original scene color to create colored pencil strokes.</p>

      <p>There are actually three different pencil stroke patterns, each aligned in a different direction, but these are combined into the red, green, and blue channels of a single texture so the shader can look up all three in a single operation.</p>
      
      <img src="Documentation/NonPhotoRealisticSketch.png">

      <p>Each of these stroke patterns is keyed off a different color channel of the input scene color, so the direction of the output strokes depends on the color of the input. You can see this most clearly if you select the monochrome "Pencil" settings in the sample. Notice how the blue background is shaded along the diagonal from top left to bottom right, while the orange spaceship contains mostly horizontal strokes, and the black cockpit cover is crosshatched along both diagonals at the same time.</p>

      <p>You may notice that the red channel of the stroke texture is aligned along the top left to bottom right diagonal, but in the final rendering it is the blue background that picks up this stroke direction. Likewise, the orange spaceship is picking up the horizontal stroke direction, which comes from the blue channel of the input stroke texture. Why are these color channels not matching up?</p>

      <p>In fact they do match up, but in a subtractive color space. In computer graphics we normally represent colors using an additive format, where we start out with zero and then add in some amounts of red, green, and blue to create whatever color we like (if we add lots of all three, we eventually end up with white). This is how computer monitors and televisions display images, so it makes a lot of sense when dealing with computer images. In the physical world, however, painters work with subtractive color, which is the exact opposite. They start out with a blank white canvas, and then paint colored pigments over the top of it. Each pigment absorbs some amount of color, subtracting that from the incoming light, until eventually they end up with black. This difference between additive and subtractive color spaces can cause a lot of confusion when computer people talk to real-world artists. A computer guy will tell you that the three primary colors are red, green, and blue, but an artist will insist they are actually red, yellow, and blue. They are being slightly inaccurate when they say this, but not as crazy as it might initally seem. What they really mean are magenta, yellow, and cyan, and they are simplifying by ignoring the small differences between magenta/red and cyan/blue. Magenta, yellow, and cyan are the primary colors of subtractive space, and are the exact opposites of the additive primary colors red, green, and blue. For instance if you start with white and subtract cyan, you get the same result as if you started with black and added red.</p>

      <p>Pencil sketching is a physical process involving colored ink on white paper, so to get convincing results we need to calculate it in a subtractive color space. We do this by subtracting our additive format input colors from 1 (white) at the start of the computation, and later repeat the same conversion to convert our subtractive result back into additive format. Because we are applying the sketch effect in a subtractive color space, everything comes out inverted to how you might expect. For instance in subtractive color the sky is not really blue, but actually "white minus red," and thus it is the red channel of the stroke texture that picks up the need to darken down that region of the screen.</p>
      
      <p>The pencil stroke pattern is animated by the <b>Game.Update</b> method, which periodically shifts it sideways by a random offset. This is a hack to emulate the way real hand-drawn animations tend to be displayed at very low framerates, typically as little as 10 or 15 frames per second. It would look terrible if we slowed all of our rendering down to such a low speed (nobody wants to play a game at 10 frames per second!) but it also looks bad if we animate the stroke texture at the same high framerate as the rest of our drawing, because it flickers too quickly to actually see the pattern and ends up just looking like random noise. The compromise is to render the scene at as high a framerate as possible, but only update the texture animation at a lower speed, thus preserving some of the appearance of a hand-drawn animation even though we are actually rendering at 60 frames per second.</p>

    </div>
  </div>

</div><div class="footer" id="footer"><p>© 2007 Microsoft Corporation. All rights reserved.<br>Send feedback to <a href="mailto:xna@microsoft.com?subject=Documentation Feedback: Non-Realistic Rendering Sample">xna@microsoft.com</a>.</p></div></div></body></html>